﻿/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;

namespace DaveSexton.DocProject
{
	[Serializable]
	[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Multi")]
	public sealed class KeywordMultiCollection : KeyedCollection<Keyword, KeywordCollection>
	{
		#region Public Properties
		public ICollection<Keyword> Keys
		{
			get
			{
				// In testing, Dictionary was null when the collection was empty
				return (base.Dictionary != null) ? base.Dictionary.Keys
					: new List<Keyword>(0).AsReadOnly();
			}
		}
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="KeywordMultiCollection" /> class.
		/// </summary>
		public KeywordMultiCollection()
		{
		}
		#endregion

		#region Methods
		protected override Keyword GetKeyForItem(KeywordCollection item)
		{
			return item.Root;
		}

		protected override void ClearItems()
		{
			if (Count > 0)
			{
				foreach (KeywordCollection collection in this)
					collection.Changed -= item_Changed;

				base.ClearItems();

				OnChanged(EventArgs.Empty);
			}
		}

		protected override void InsertItem(int index, KeywordCollection item)
		{
			if (item == null)
				throw new ArgumentNullException("item");

			item.Changed += item_Changed;

			base.InsertItem(index, item);

			OnChanged(EventArgs.Empty);
		}

		protected override void SetItem(int index, KeywordCollection item)
		{
			if (item == null)
				throw new ArgumentNullException("item");

			KeywordCollection oldItem = this[index];
			oldItem.Changed -= item_Changed;

			item.Changed += item_Changed;

			base.SetItem(index, item);

			OnChanged(EventArgs.Empty);
		}

		protected override void RemoveItem(int index)
		{
			KeywordCollection item = this[index];
			item.Changed -= item_Changed;

			base.RemoveItem(index);

			OnChanged(EventArgs.Empty);
		}
		#endregion

		#region Events
		private readonly object ChangedEventLock = new object();
		private EventHandler ChangedEvent;

		/// <summary>
		/// Event raised when the collection or any nested collection changes.
		/// </summary>
		public event EventHandler Changed
		{
			add
			{
				lock (ChangedEventLock)
				{
					ChangedEvent += value;
				}
			}
			remove
			{
				lock (ChangedEventLock)
				{
					ChangedEvent -= value;
				}
			}
		}

		/// <summary>
		/// Raises the <see cref="Changed" /> event.
		/// </summary>
		/// <param name="e"><see cref="EventArgs" /> object that provides the arguments for the event.</param>
		private void OnChanged(EventArgs e)
		{
			EventHandler handler = null;

			lock (ChangedEventLock)
			{
				handler = ChangedEvent;
			}

			if (handler != null)
				handler(this, e);
		}
		#endregion

		#region Event Handlers
		private void item_Changed(object sender, EventArgs e)
		{
			OnChanged(EventArgs.Empty);
		}
		#endregion
	}
}
